package com.syf.starter.core.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;

import java.util.concurrent.CountDownLatch;

@Slf4j
public abstract class SyAbstractNettyServer {
    private final NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);

    private NioEventLoopGroup workGroup;

    private ServerBootstrap bootstrap;

    private ChannelFuture bindFuture;

    private SyNettyServerConfig config;

    /**
     * 设置Handle Pipeline
     */
    public abstract ChannelInitializer buildChannelInitializer();


    public void initServer(SyNettyServerConfig config) {
        this.config = config;

        this.workGroup = new NioEventLoopGroup(new CustomizableThreadFactory(config.getServerName().concat("-worker")));
        this.bootstrap = new ServerBootstrap()
                .group(bossGroup, workGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(buildChannelInitializer())
                .childOption(ChannelOption.SO_KEEPALIVE, config.getIS_KEEP_ALIVE())
                .option(ChannelOption.SO_BACKLOG, config.getTCP_SO_BACKLOG())
                .option(ChannelOption.SO_RCVBUF, config.getTCP_SO_RCVBUF());
    }

    public void startServer(CountDownLatch latch) {
        try {
            bindFuture = bootstrap.bind(config.getHost(), config.getPort())
                    .addListener(future -> {
                        if (future.isSuccess()) {
                            log.info("{}[{}:{}] had started,", config.getServerName(), config.getHost(), config.getPort());
                            latch.countDown();
                        } else {
                            log.error("{}[{}:{}] start failure", config.getServerName(), config.getHost(), config.getPort());
                            throw new RuntimeException("NETTY SERVER[" + config.getServerName() + "] 启动异常！");
                        }
                    }).sync();
            bindFuture.channel().closeFuture().addListener(future -> {
                if (future.isSuccess()) {
                    log.info("{}[{}:{}] is closed", config.getServerName(), config.getHost(), config.getPort());
                }
            }).sync();
        } catch (InterruptedException e) {
            log.error("{}[{}:{}] 启动失败，出现异常！", config.getServerName(), config.getHost(), config.getPort());
            throw new RuntimeException(e);
        } finally {
            bossGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        }
    }

    public void stopServer() {
        bindFuture.channel().close();
    }
}
